/*
*  modifier: Honrun
*  date:     2023/10/29 20:42
*/
#include "stdio.h"
#include "string.h"
#include "DevicesMemHeap.h"


/* 字节对齐 */
#define HEAP_ROUNDUP_VALUE      sizeof(uint32_t)
/* 使x对n字节对齐 */
#define heapRoundUp(x)          (((x) + (HEAP_ROUNDUP_VALUE) - 1) & (~((HEAP_ROUNDUP_VALUE) - 1)))
#define HEAP_REG(addr)          (*(volatile uint32_t *)((uint32_t)(addr)))

/* 动态内存头部信息 */
MemHeapType g_typeMemHeapHead = {0};
/* 模拟内存大小  */
#define DEFAULT_MEMORY_SIZE     102400
/* 需要增加 HEAP_ROUNDUP_VALUE个字节，以使字节对齐 */
uint8_t st_ucMemHeapBuff[DEFAULT_MEMORY_SIZE + HEAP_ROUNDUP_VALUE] = {0};


void vMemHeapInit(void)
{
    vMemHeapCreate(&g_typeMemHeapHead, st_ucMemHeapBuff, sizeof(st_ucMemHeapBuff) - HEAP_ROUNDUP_VALUE);
}

void vMemHeapCreate(MemHeapType *ptypeHanle, void *pvMem, size_t size)
{
    if((ptypeHanle == NULL) || (pvMem == NULL) || (size < 1))
        return;

    /* 地址 N 字节对齐 */
    ptypeHanle->head = heapRoundUp((uint32_t)pvMem);
    ptypeHanle->tail = ptypeHanle->head + size;

    /* 初始化第一个空闲空间 */
    HEAP_REG(ptypeHanle->head) = ptypeHanle->tail;
}

void *pvMemHeapMalloc(MemHeapType *ptypeHanle, size_t size)
{
    void *pvHandle = NULL;
    uint32_t uiHead, uiTail, uiMinHead = 0;
    uint32_t uiNowSize, uiMinSize = 0x7FFFFFFF;

    if((ptypeHanle == NULL) || (ptypeHanle->head == 0) || (size < 1))
        return NULL;

    /* 长度 N 字节对齐 */
    size = heapRoundUp(size);

    /* 遍历mem空间 */
    for(uiHead = ptypeHanle->head; uiHead < ptypeHanle->tail; uiHead = HEAP_REG(uiHead) & 0xFFFFFFFE)
    {
        if((HEAP_REG(uiHead) & 1) == 0)
        {
            uiNowSize = HEAP_REG(uiHead) - uiHead - sizeof(uint32_t);

            /* 最小空闲匹配 */
            if((uiNowSize >= size) && (uiNowSize < uiMinSize))
            {
                uiMinSize = uiNowSize;
                uiMinHead = uiHead;

                if(uiMinSize == size)
                    break;
            }
        }
    }

    if(uiMinHead != 0)
    {
        /* 最小匹配空间被划分后还有剩余空间，并能够存储下一个头部信息 */
        if((uiMinSize - size) >= sizeof(uint32_t))
        {
            uiTail = HEAP_REG(uiMinHead);
            HEAP_REG(uiMinHead) = uiMinHead + sizeof(uint32_t) + size;

            /* 剩余的空闲空间 */
            HEAP_REG(HEAP_REG(uiMinHead)) = uiTail;
        }

        /* 返回空间管理信息之后的空间地址 */
        pvHandle = (void *)(uiMinHead + sizeof(uint32_t));

        /* 起始地址最低置1，表示已使用 */
        HEAP_REG(uiMinHead) |= 1;
    }

    return pvHandle;
}

void *pvMemHeapCalloc(MemHeapType *ptypeHanle, size_t nitems, size_t size)
{
    void *pvHandle;
    uint32_t *puiData;

    /* 长度 N 字节对齐 */
    size = heapRoundUp(nitems * size);

    if((pvHandle = pvMemHeapMalloc(ptypeHanle, size)) != NULL)
    {
        for(puiData = pvHandle, size >>= 2; size > 0; --size)
        {
            *puiData++ = 0;
        }
    }

    return pvHandle;
}

void *pvMemHeapRealloc(MemHeapType *ptypeHanle, void *pvMem, size_t size)
{
    void *pvHandle;
    uint32_t uiHead, uiTail, uiNext;
    uint32_t *puiTarget, *puiSource, uiFreeSize;

    if((ptypeHanle == NULL) || (ptypeHanle->head == 0) || (pvMem == NULL) || (size < 1))
        return NULL;

    /* 位移到头部管理信息位置 */
    uiHead = (uint32_t)pvMem - sizeof(uint32_t);
    if((uiHead < ptypeHanle->head) || (ptypeHanle->tail <= uiHead))
        return NULL;

    /* 长度 N 字节对齐 */
    size = heapRoundUp(size);

    /* 计算后续衔接空闲空间的大小 */
    uiTail = HEAP_REG(uiHead) & 0xFFFFFFFE;
    uiTail = ((HEAP_REG(uiTail) & 1) == 0) && (uiTail < ptypeHanle->tail) ? HEAP_REG(uiTail) : uiTail;

    uiFreeSize = uiTail - uiHead - sizeof(uint32_t);

    /* 直接拓展衔接的空闲空间 */
    if(uiFreeSize >= size)
    {
        /* 多余的空间能够存储一个头部信息 */
        if((uiFreeSize - size) >= sizeof(uint32_t))
        {
            /* 截断成多余的空闲空间 */
            uiNext = uiHead + sizeof(uint32_t) + size;
            HEAP_REG(uiNext) = uiTail;

            uiTail = uiNext;
        }

        HEAP_REG(uiHead) = uiTail | 1;

        pvHandle = pvMem;
    }
    /* 重新分配空间 */
    else if((pvHandle = pvMemHeapMalloc(ptypeHanle, size)) != NULL)
    {
        /* 转移拷贝数据 */
        for(puiTarget = (uint32_t *)pvHandle, puiSource = (uint32_t *)pvMem, size >>= 2; size > 0; --size)
        {
            *puiTarget++ = *puiSource++;
        }

        /* 释放旧空间 */
        vMemHeapFree(ptypeHanle, pvMem);
    }

    return pvHandle;
}

void vMemHeapFree(MemHeapType *ptypeHanle, void *pvMem)
{
    uint32_t uiHead, uiPrev, uiNext;

    if((ptypeHanle == NULL) || (ptypeHanle->head == 0) || (pvMem == NULL))
        return;

    /* 位移到头部管理信息位置 */
    uiHead = (uint32_t)pvMem - sizeof(uint32_t);
    if((uiHead < ptypeHanle->head) || (ptypeHanle->tail <= uiHead))
        return;

    if((HEAP_REG(uiHead) & 1) != 0)
    {
        /* 最低位清零，表示释放此片内存 */
        HEAP_REG(uiHead) &= 0xFFFFFFFE;

        /* 遍历，找到当前待删除空间的前面一个空间 */
        for(uiPrev = ptypeHanle->head; HEAP_REG(uiPrev) < uiHead; uiPrev = HEAP_REG(uiPrev) & 0xFFFFFFFE);

        /* 合并前面一个相连的空闲空间 */
        if((HEAP_REG(uiPrev) & 1) == 0)
        {
            HEAP_REG(uiPrev) = HEAP_REG(uiHead);
            uiHead = uiPrev;
        }

        /* 合并后面一个相连的空闲空间 */
        uiNext = HEAP_REG(uiHead);
        if(((HEAP_REG(uiNext) & 1) == 0) && (uiNext < ptypeHanle->tail))
        {
            HEAP_REG(uiHead) = HEAP_REG(uiNext);
        }
    }
}
